# -*- coding: utf-8 -*-
"""
心理咨询师服务系统 - 用户服务
"""

from typing import Dict, List, Optional, Tuple, Any
from datetime import datetime, timedelta
from flask import current_app
from werkzeug.security import generate_password_hash, check_password_hash
from sqlalchemy.exc import IntegrityError
from sqlalchemy import and_, or_

from ..models import User, UserBasicInfo, UserMembership, UserAgreementConfirmation
from ..models import db
from ..utils.helpers import generate_random_string, validate_email, validate_phone
from ..utils.validators import validate_password_strength, validate_username, validate_basic_info_data


class UserService:
    """用户服务类"""
    
    @staticmethod
    def create_user(username: str, email: str, password: str, 
                   phone: Optional[str] = None, 
                   basic_info: Optional[Dict[str, Any]] = None) -> Tuple[bool, str, Optional[User]]:
        """创建用户
        
        Args:
            username: 用户名
            email: 邮箱
            password: 密码
            phone: 手机号（可选）
            basic_info: 基础信息（可选）
        
        Returns:
            (是否成功, 消息, 用户对象)
        """
        try:
            # 验证用户名
            is_valid, msg = validate_username(username)
            if not is_valid:
                return False, msg, None
            
            # 验证邮箱
            if not validate_email(email):
                return False, '邮箱格式错误', None
            
            # 验证密码
            is_valid, msg = validate_password_strength(password)
            if not is_valid:
                return False, msg, None
            
            # 验证手机号
            if phone and not validate_phone(phone):
                return False, '手机号格式错误', None
            
            # 验证基础信息
            if basic_info:
                is_valid, msg = validate_basic_info_data(basic_info)
                if not is_valid:
                    return False, msg, None
            
            # 检查用户名是否已存在
            if User.query.filter_by(username=username).first():
                return False, '用户名已存在', None
            
            # 检查邮箱是否已存在
            if User.query.filter_by(email=email).first():
                return False, '邮箱已被注册', None
            
            # 检查手机号是否已存在
            if phone and User.query.filter_by(phone=phone).first():
                return False, '手机号已被注册', None
            
            # 创建用户
            user = User(
                username=username,
                email=email,
                password_hash=generate_password_hash(password),
                phone=phone,
                status='active'
            )
            
            db.session.add(user)
            db.session.flush()  # 获取用户ID
            
            # 创建基础信息记录
            if basic_info:
                user_basic_info = UserBasicInfo(
                    user_id=user.id,
                    **basic_info
                )
                db.session.add(user_basic_info)
            
            # 创建会员信息记录
            from datetime import date, timedelta
            user_membership = UserMembership(
                user_id=user.id,
                plan_type='basic',
                status='active',
                start_date=date.today(),
                end_date=date.today() + timedelta(days=36500)  # 100年后过期，相当于永不过期
            )
            db.session.add(user_membership)
            
            db.session.commit()
            
            return True, '用户创建成功', user
            
        except IntegrityError as e:
            db.session.rollback()
            current_app.logger.error(f'用户创建失败 - 数据完整性错误: {str(e)}')
            return False, '用户信息冲突，请检查用户名、邮箱或手机号', None
        except Exception as e:
            db.session.rollback()
            current_app.logger.error(f'用户创建失败: {str(e)}')
            return False, '用户创建失败，请稍后重试', None
    
    @staticmethod
    def authenticate_user(identifier: str, password: str) -> Tuple[bool, str, Optional[User]]:
        """用户认证
        
        Args:
            identifier: 用户标识（用户名、邮箱或手机号）
            password: 密码
        
        Returns:
            (是否成功, 消息, 用户对象)
        """
        try:
            # 查找用户（支持用户名、邮箱、手机号登录）
            user = User.query.filter(
                or_(
                    User.username == identifier,
                    User.email == identifier,
                    User.phone == identifier
                )
            ).first()
            
            if not user:
                return False, '用户不存在', None
            
            # 检查用户状态
            if user.status == 'inactive':
                return False, '账户未激活，请先激活账户', None
            elif user.status == 'suspended':
                return False, '账户已被暂停，请联系管理员', None
            elif user.status == 'deleted':
                return False, '账户已被删除', None
            
            # 验证密码
            if not user.check_password(password):
                # 记录登录失败
                user.failed_login_attempts += 1
                user.last_failed_login = datetime.utcnow()
                
                # 检查是否需要锁定账户
                if user.failed_login_attempts >= current_app.config.get('MAX_LOGIN_ATTEMPTS', 5):
                    user.status = 'suspended'
                    db.session.commit()
                    return False, '登录失败次数过多，账户已被暂停', None
                
                db.session.commit()
                return False, '密码错误', None
            
            # 登录成功，更新登录信息
            user.update_login_info()
            db.session.commit()
            
            return True, '登录成功', user
            
        except Exception as e:
            current_app.logger.error(f'用户认证失败: {str(e)}')
            return False, '登录失败，请稍后重试', None
    
    @staticmethod
    def update_user_profile(user_id: int, data: Dict[str, Any]) -> Tuple[bool, str]:
        """更新用户资料
        
        Args:
            user_id: 用户ID
            data: 更新数据
        
        Returns:
            (是否成功, 消息)
        """
        try:
            user = User.get_by_id(user_id)
            if not user:
                return False, '用户不存在'
            
            # 可更新的字段
            allowed_fields = ['username', 'email', 'phone', 'avatar_url']
            
            for field in allowed_fields:
                if field in data:
                    value = data[field]
                    
                    # 特殊验证
                    if field == 'username':
                        is_valid, msg = validate_username(value)
                        if not is_valid:
                            return False, msg
                        
                        # 检查用户名是否已被其他用户使用
                        existing_user = User.query.filter(
                            and_(User.username == value, User.id != user_id)
                        ).first()
                        if existing_user:
                            return False, '用户名已被使用'
                    
                    elif field == 'email':
                        if not validate_email(value):
                            return False, '邮箱格式错误'
                        
                        # 检查邮箱是否已被其他用户使用
                        existing_user = User.query.filter(
                            and_(User.email == value, User.id != user_id)
                        ).first()
                        if existing_user:
                            return False, '邮箱已被使用'
                    
                    elif field == 'phone':
                        if value and not validate_phone(value):
                            return False, '手机号格式错误'
                        
                        # 检查手机号是否已被其他用户使用
                        if value:
                            existing_user = User.query.filter(
                                and_(User.phone == value, User.id != user_id)
                            ).first()
                            if existing_user:
                                return False, '手机号已被使用'
                    
                    setattr(user, field, value)
            
            db.session.commit()
            return True, '资料更新成功'
            
        except IntegrityError as e:
            db.session.rollback()
            current_app.logger.error(f'用户资料更新失败 - 数据完整性错误: {str(e)}')
            return False, '资料更新失败，请检查输入信息'
        except Exception as e:
            db.session.rollback()
            current_app.logger.error(f'用户资料更新失败: {str(e)}')
            return False, '资料更新失败，请稍后重试'
    
    @staticmethod
    def update_basic_info(user_id: int, basic_info: Dict[str, Any]) -> Tuple[bool, str]:
        """更新用户基础信息
        
        Args:
            user_id: 用户ID
            basic_info: 基础信息
        
        Returns:
            (是否成功, 消息)
        """
        try:
            # 验证基础信息
            is_valid, msg = validate_basic_info_data(basic_info)
            if not is_valid:
                return False, msg
            
            # 查找或创建基础信息记录
            user_basic_info = UserBasicInfo.query.filter_by(user_id=user_id).first()
            
            if user_basic_info:
                # 更新现有记录
                user_basic_info.update_from_dict(basic_info)
            else:
                # 创建新记录
                user_basic_info = UserBasicInfo(
                    user_id=user_id,
                    **basic_info
                )
                db.session.add(user_basic_info)
            
            db.session.commit()
            return True, '基础信息更新成功'
            
        except Exception as e:
            db.session.rollback()
            current_app.logger.error(f'用户基础信息更新失败: {str(e)}')
            return False, '基础信息更新失败，请稍后重试'
    
    @staticmethod
    def change_password(user_id: int, old_password: str, new_password: str) -> Tuple[bool, str]:
        """修改密码
        
        Args:
            user_id: 用户ID
            old_password: 旧密码
            new_password: 新密码
        
        Returns:
            (是否成功, 消息)
        """
        try:
            user = User.get_by_id(user_id)
            if not user:
                return False, '用户不存在'
            
            # 验证旧密码
            if not user.check_password(old_password):
                return False, '原密码错误'
            
            # 验证新密码
            is_valid, msg = validate_password_strength(new_password)
            if not is_valid:
                return False, msg
            
            # 检查新密码是否与旧密码相同
            if user.check_password(new_password):
                return False, '新密码不能与原密码相同'
            
            # 更新密码
            user.password_hash = generate_password_hash(new_password)
            user.password_changed_at = datetime.utcnow()
            
            db.session.commit()
            return True, '密码修改成功'
            
        except Exception as e:
            db.session.rollback()
            current_app.logger.error(f'密码修改失败: {str(e)}')
            return False, '密码修改失败，请稍后重试'
    
    @staticmethod
    def reset_password(email: str) -> Tuple[bool, str, Optional[str]]:
        """重置密码
        
        Args:
            email: 邮箱
        
        Returns:
            (是否成功, 消息, 重置令牌)
        """
        try:
            user = User.query.filter_by(email=email).first()
            if not user:
                return False, '邮箱不存在', None
            
            if user.status != 'active':
                return False, '账户状态异常，无法重置密码', None
            
            # 生成重置令牌
            reset_token = generate_random_string(32)
            user.password_reset_token = reset_token
            user.password_reset_expires = datetime.utcnow() + timedelta(hours=1)
            
            db.session.commit()
            
            return True, '重置令牌已生成', reset_token
            
        except Exception as e:
            db.session.rollback()
            current_app.logger.error(f'密码重置失败: {str(e)}')
            return False, '密码重置失败，请稍后重试', None
    
    @staticmethod
    def confirm_password_reset(token: str, new_password: str) -> Tuple[bool, str]:
        """确认密码重置
        
        Args:
            token: 重置令牌
            new_password: 新密码
        
        Returns:
            (是否成功, 消息)
        """
        try:
            user = User.query.filter_by(password_reset_token=token).first()
            if not user:
                return False, '重置令牌无效'
            
            if user.password_reset_expires < datetime.utcnow():
                return False, '重置令牌已过期'
            
            # 验证新密码
            is_valid, msg = validate_password_strength(new_password)
            if not is_valid:
                return False, msg
            
            # 更新密码
            user.password_hash = generate_password_hash(new_password)
            user.password_changed_at = datetime.utcnow()
            user.password_reset_token = None
            user.password_reset_expires = None
            
            db.session.commit()
            return True, '密码重置成功'
            
        except Exception as e:
            db.session.rollback()
            current_app.logger.error(f'密码重置确认失败: {str(e)}')
            return False, '密码重置失败，请稍后重试'
    
    @staticmethod
    def get_user_list(page: int = 1, per_page: int = 20, 
                     search: Optional[str] = None,
                     status: Optional[str] = None,
                     membership_type: Optional[str] = None) -> Dict[str, Any]:
        """获取用户列表
        
        Args:
            page: 页码
            per_page: 每页数量
            search: 搜索关键词
            status: 用户状态
            membership_type: 会员类型
        
        Returns:
            分页用户数据
        """
        try:
            query = User.query
            
            # 搜索条件
            if search:
                search_pattern = f'%{search}%'
                query = query.filter(
                    or_(
                        User.username.like(search_pattern),
                        User.email.like(search_pattern),
                        User.phone.like(search_pattern)
                    )
                )
            
            # 状态筛选
            if status:
                query = query.filter(User.status == status)
            
            # 会员类型筛选
            if membership_type:
                query = query.join(UserMembership).filter(
                    UserMembership.plan_type == membership_type
                )
            
            # 排序
            query = query.order_by(User.created_at.desc())
            
            # 分页
            pagination = query.paginate(
                page=page,
                per_page=per_page,
                error_out=False
            )
            
            return {
                'users': [user.to_dict() for user in pagination.items],
                'total': pagination.total,
                'pages': pagination.pages,
                'current_page': page,
                'per_page': per_page,
                'has_prev': pagination.has_prev,
                'has_next': pagination.has_next
            }
            
        except Exception as e:
            current_app.logger.error(f'获取用户列表失败: {str(e)}')
            return {
                'users': [],
                'total': 0,
                'pages': 0,
                'current_page': page,
                'per_page': per_page,
                'has_prev': False,
                'has_next': False
            }
    
    @staticmethod
    def confirm_agreement(user_id: int, agreement_type: str, version: str) -> Tuple[bool, str]:
        """确认用户协议
        
        Args:
            user_id: 用户ID
            agreement_type: 协议类型
            version: 协议版本
        
        Returns:
            (是否成功, 消息)
        """
        try:
            # 检查是否已确认过该版本的协议
            existing_confirmation = UserAgreementConfirmation.query.filter_by(
                user_id=user_id,
                agreement_type=agreement_type,
                version=version
            ).first()
            
            if existing_confirmation:
                return True, '协议已确认'
            
            # 创建确认记录
            confirmation = UserAgreementConfirmation(
                user_id=user_id,
                agreement_type=agreement_type,
                version=version,
                confirmed_at=datetime.utcnow()
            )
            
            db.session.add(confirmation)
            db.session.commit()
            
            return True, '协议确认成功'
            
        except Exception as e:
            db.session.rollback()
            current_app.logger.error(f'协议确认失败: {str(e)}')
            return False, '协议确认失败，请稍后重试'